/**
 * @file Vite配置工具函数
 * @description 提供Vite配置的工具函数，用于减少重复代码和提高配置的可维护性
 * @author 黄敏
 * @version 1.0.0
 * @since 2025-06-27
 */

import type { BuildEnvironmentOptions, Plugin } from 'vite'
import { resolve } from 'node:path'
import { sentryVitePlugin } from '@sentry/vite-plugin'
import { loadEnv } from 'vite'
// 轻量本地类型，避免依赖 rollup 的类型包
// 仅用于我们的小插件在预加载 CJS 产物中做字符串替换
interface SimpleOutputFile {
  type: 'chunk' | 'asset'
  code?: string
}

/**
 * Sentry配置接口
 */
interface SentryConfig {
  /** 组织名称 */
  org?: string
  /** 项目名称 */
  project?: string
  /** 认证令牌 */
  authToken?: string
  /** 版本号 */
  version?: string
}

/**
 * 构建配置选项接口
 */
interface BuildConfigOptions {
  /** 输出目录 */
  outputDir: string
  /** 模块格式 */
  format: 'esm' | 'cjs'
  /** 是否生成源映射 */
  sourcemap?: boolean
}

/**
 * 加载环境变量
 * @param mode - 构建模式
 * @returns 环境变量对象
 */
export function loadEnvironmentVariables(mode: string) {
  // Vite 会自动加载 .env, .env.local, .env.[mode], .env.[mode].local 文件
  const env = loadEnv(mode, process.cwd(), '')

  // 将环境变量设置到 process.env 中
  Object.assign(process.env, env)

  console.log(`✓ 已加载 ${mode} 模式的环境变量`)
  return env
}

/**
 * 创建共享的 define 配置
 * @param env - 环境变量对象
 * @param mode - 构建模式
 * @returns define 配置对象
 */
export function createSharedDefineConfig(env: Record<string, string>, mode: string) {
  return {
    // 环境变量
    'process.env.NODE_ENV': JSON.stringify(env.NODE_ENV || mode),
    'process.env.npm_package_version': JSON.stringify(process.env.npm_package_version),
    'process.env.npm_package_name': JSON.stringify(process.env.npm_package_name),
    // Sentry 配置
    'process.env.SENTRY_DSN': JSON.stringify(env.SENTRY_DSN),
    'process.env.SENTRY_ORG': JSON.stringify(env.SENTRY_ORG),
    'process.env.SENTRY_PROJECT': JSON.stringify(env.SENTRY_PROJECT),
    'process.env.SENTRY_AUTH_TOKEN': JSON.stringify(env.SENTRY_AUTH_TOKEN),
    // Node.js 兼容性变量 (仅用于主进程)
    __filename: 'import.meta.url',
    __dirname: 'import.meta.dirname'
  }
}

/**
 * 创建共享的构建配置
 * @param options - 构建配置选项
 * @returns Vite构建配置
 */
export function createSharedBuildConfig(options: BuildConfigOptions): BuildEnvironmentOptions {
  const { outputDir, format, sourcemap = true } = options

  return {
    sourcemap,
    rollupOptions: {
      output: {
        format,
        dir: outputDir,
        // 确保 CJS 构建产物使用 .cjs 扩展名，避免受 package.json "type": "module" 影响
        entryFileNames: format === 'cjs' ? '[name].cjs' : '[name].js'
      },
      external: [
        // Node.js 内置模块
        'electron',
        'fs',
        'path',
        'os',
        'crypto',
        'util',
        'events',
        'stream',
        'buffer',
        'url',
        // 原生模块
        'better-sqlite3',
        // 其他需要外部化的模块
        /^node:/
      ]
    }
  }
}

/**
 * 为主进程和预加载脚本创建Sentry插件配置
 * @param outputDir - 输出目录
 * @param mode - 构建模式
 * @param config - Sentry配置
 * @returns Sentry插件实例或null
 */
export function createSentryPlugin(outputDir: string, mode: string, config: SentryConfig = {}) {
  // 只在生产构建时启用Sentry插件
  if (mode !== 'production') {
    return null
  }

  const {
    org = process.env.SENTRY_ORG,
    project = process.env.SENTRY_PROJECT,
    authToken = process.env.SENTRY_AUTH_TOKEN,
    version = process.env.npm_package_version || '0.0.1'
  } = config

  // 如果没有配置 authToken，则禁用 Sentry 插件
  if (!authToken) {
    console.log('⚠️  Sentry authToken 未配置，跳过 Sentry 插件')
    return null
  }

  return sentryVitePlugin({
    org,
    project,
    authToken,
    sourcemaps: {
      assets: [`${outputDir}/**`],
      ignore: ['node_modules/**'],
      filesToDeleteAfterUpload: [`${outputDir}/**/*.map`]
    },
    release: {
      name: `field-flint@${version}`,
      setCommits: {
        auto: true
      }
    },
    silent: false,
    debug: false
  })
}

/**
 * 创建主进程和预加载脚本的路径别名配置
 * @returns 路径别名配置对象
 */
function createElectronAliases(libraryPath: 'preloads' | 'main') {
  // 获取项目根目录
  const projectRoot = resolve(process.cwd())

  return {
    '#': resolve(projectRoot, 'srcMain'),
    '~shared': resolve(projectRoot, 'srcShared'),
    '~types': resolve(projectRoot, 'srcShared/types'),
    'global-state': resolve(projectRoot, `library/global-state/${libraryPath}`)
  }
}

/**
 * 创建Electron插件配置
 * @param entry - 入口文件路径
 * @param outputDir - 输出目录
 * @param format - 模块格式
 * @param mode - 构建模式
 * @param env - 环境变量对象
 * @param onStart - 启动回调函数
 * @returns Electron插件配置
 */
export function createElectronConfig(
  entry: string,
  outputDir: string,
  format: 'esm' | 'cjs',
  mode: string,
  env: Record<string, string>,
  onStart?: () => void
) {
  return {
    entry,
    onstart: onStart,
    vite: {
      define: createSharedDefineConfig(env, mode),
      // 修复部分情况下 CJS 产物末尾出现 `export default` 的问题（Electron 预加载不支持 ESM）
      plugins: [
        createSentryPlugin(outputDir, mode) as unknown as Plugin,
        ...(format === 'cjs'
          ? [
              {
                name: 'fix-cjs-export-for-preload',
                apply: 'build' as const,
                generateBundle(this: unknown, _options: unknown, bundle: unknown) {
                  const files = Object.values(bundle as Record<string, unknown>)
                  for (const f of files) {
                    const file = f as SimpleOutputFile
                    if (file.type === 'chunk' && typeof file.code === 'string') {
                      let code = file.code
                      // 将 `export default X` 强制改为 `module.exports = X`
                      code = code.replace(/\nexport default /g, '\nmodule.exports = ')
                      code = code.replace(/^export default /m, 'module.exports = ')
                      file.code = code
                    }
                  }
                }
              } as Plugin
            ]
          : [])
      ].filter(Boolean),

      resolve: {
        alias: createElectronAliases(outputDir === 'dist/preloads' ? 'preloads' : 'main')
      },
      build: {
        ...createSharedBuildConfig({ outputDir, format, sourcemap: true }),
        // 仅在 ESM 输出时启用 SSR 构建；CJS 预加载关闭 SSR，确保产物为纯 CJS（require）
        ssr: format === 'esm'
      },
      // 强制将 vue 打包进主进程产物，避免安装版找不到模块
      ssr:
        format === 'esm'
          ? {
              noExternal: ['@vue/reactivity', 'lodash', '@mdi/js']
            }
          : undefined
    }
  }
}

/**
 * 日志构建信息
 * @param mode - 构建模式
 */
export function logBuildInfo(mode: string): void {
  const version = process.env.npm_package_version || '0.0.1'

  console.log('🚀 构建信息:')
  console.log(`   模式: ${mode}`)
  console.log(`   版本: ${version}`)
  console.log(`   时间戳: ${new Date().toISOString()}`)
  console.log(`   Node.js: ${process.version}`)
  console.log(`   平台: ${process.platform}-${process.arch}`)
}
